package com.ly.system.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ly.common.core.bean.R;
import com.ly.common.core.bean.dto.CommonBatchUpdateDTO;
import com.ly.common.core.bean.vo.DictVO;
import com.ly.common.core.constant.BaseCacheConstant;
import com.ly.common.core.constant.BaseConstant;
import com.ly.common.core.utils.RedisUtils;
import com.ly.common.core.utils.SqlUtils;
import com.ly.system.mapper.SysDictMapper;
import com.ly.system.service.ISysDictService;
import com.ly.system.system.bean.dto.FieldCheckDTO;
import com.ly.system.system.bean.entity.SysDict;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 字典-服务
 *
 * @author jeecg
 * @since 2018-12-28
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> implements ISysDictService {

    private final SysDictMapper sysDictMapper;
    private final RedisUtils redisUtil;

    @Override
    public R getId(String id) {
        SysDict entity = this.getById(id);
        if (entity == null) {
            return R.fail("未找到对应数据");
        }
        return R.ok(entity);
    }

    @Override
    public R getList(SysDict entity) {
        List<SysDict> list = this.list(new LambdaQueryWrapper<SysDict>().orderByDesc(SysDict::getCreateTime));
        return R.ok(list);
    }

    @Override
    public R getPage(SysDict entity, Page<SysDict> page) {
        IPage<SysDict> pageList = this.page(
                page,
                new LambdaQueryWrapper<SysDict>()
                        .like(StrUtil.isNotBlank(entity.getDictCode()), SysDict::getDictCode, entity.getDictCode())
                        .like(StrUtil.isNotBlank(entity.getDictName()), SysDict::getDictName, entity.getDictName())
                        .and(StrUtil.isNotBlank(entity.getKeywords()),
                                i -> i.like(SysDict::getDictCode, entity.getKeywords())
                                        .or().like(SysDict::getDictCode, entity.getKeywords())
                        )
                        .orderByDesc(SysDict::getCreateTime));
        return R.ok(pageList);
    }

    @Override
    public R add(SysDict entity) {
        // entity.setCreateTime(new Date());
        entity.setDelFlag(BaseConstant.DEL_FLAG_0);
        boolean flag = this.save(entity);
        return flag ? R.ok(true, "创建成功") : R.fail("创建失败");
    }

    @Override
    public R edit(SysDict entity) {
        boolean flag = this.updateById(entity);
        return flag ? R.ok(true, "修改成功") : R.fail("修改失败");
    }

    @Override
    public R delete(String id) {
        boolean flag = this.removeById(id);
        return flag ? R.ok(true, "删除成功") : R.fail("删除失败");
    }

    @Override
    public R deleteBatch(String ids) {
        boolean flag = this.removeByIds(Arrays.asList(ids.split(",")));
        return flag ? R.ok(true, "批量删除成功") : R.fail("批量删除失败");
    }

    @Override
    public R updateBatch(CommonBatchUpdateDTO<SysDict> dto) {
        List<SysDict> datas = dto.getDatas();
        boolean flag = this.saveOrUpdateBatch(datas);
        return flag ? R.ok(true, "批量修改成功") : R.fail("批量修改失败");
    }

    @Override
    public R duplicateCheckData(FieldCheckDTO dto) {
        if (StrUtil.isEmpty(dto.getFieldVal())) {
            return R.ok("数据为空,不作处理！");
        }
        // 1.针对采用 ${}写法的表名和字段进行转义和check
        String table = SqlUtils.getSqlInjectTableName(dto.getTableName());
        String fieldName = SqlUtils.getSqlInjectField(dto.getFieldName());
        dto.setTableName(table);
        dto.setFieldName(fieldName);
        // 2.SQL注入check（只限制非法串改数据库） 关联表字典（sys_user,realname,id）
        SqlUtils.filterContentMulti(table, fieldName);
        Long count = sysDictMapper.duplicateCheckCountSql(dto);
        if (count != 0) {
            return R.fail("该值不可用，系统中已存在！");
        }
        return R.ok("该值可用！");
    }

    /**
     * 通过查询指定code 获取字典
     *
     * @param code
     * @return
     */
    @Override
    public List<DictVO> queryDictItemsByCode(String code) {
        log.debug("无缓存dictCache的时候调用这里！");
        return sysDictMapper.queryDictItemsByCode(code);
    }

    @Override
    public R refreshCache() {
        redisUtil.removeAll(BaseCacheConstant.SYS_DICT_CACHE);
        redisUtil.removeAll(BaseCacheConstant.SYS_ENABLE_DICT_CACHE);
        redisUtil.removeAll(BaseCacheConstant.SYS_DICT_TABLE_CACHE);
        redisUtil.removeAll(BaseCacheConstant.SYS_DICT_TABLE_BY_KEYS_CACHE);
        redisUtil.removeAll(BaseCacheConstant.SYS_1DEPARTS_CACHE);
        redisUtil.removeAll(BaseCacheConstant.SYS_1DEPART_IDS_CACHE);
        redisUtil.removeAll("jmreport:cache:dict");
        redisUtil.removeAll("jmreport:cache:dictTable");
        // 分配权限必须退出重新登录才生效，造成很多用户困扰---
        // 清除当前用户的授权缓存信息，todo：ly:集成 springsecurity 处理
        return R.ok(this.queryAllDictItems());
    }

    @Override
    public Map<String, List<DictVO>> queryAllDictItems() {
        List<DictVO> allList = sysDictMapper.queryAllDictItems(null);
        Map<String, List<DictVO>> sysAllDictItems = allList.stream().collect(Collectors.groupingBy(DictVO::getDictCode, Collectors.toList()));
        // Map<String, List<DictVO>> sysAllDictItems = allList.stream().collect(Collectors.groupingBy(
        //         DictVO::getDictCode,
        //         Collectors.mapping(d -> new DictVO(d.getValue(), d.getText(), d.getColor()), Collectors.toList()))
        // );
        return sysAllDictItems;
    }

    /**
     * 通过查询指定code 获取字典值text
     *
     * @param code
     * @param key
     * @return
     */
    @Override
    public String queryDictTextByKey(String code, String key) {
        log.debug("无缓存dictText的时候调用这里！");
        return sysDictMapper.queryDictTextByKey(code, key);
    }

    @Override
    public List<DictVO> getDictItems(String dictCode) {
        List<DictVO> ls;
        if (dictCode.contains(",")) {
            // 关联表字典（举例：sys_user,realname,id）
            String[] params = dictCode.split(",");
            if (params.length < 3) {
                // 字典Code格式不正确
                return null;
            }
            if (params.length == 4) {
                ls = this.queryTableDictItemsByCodeAndFilter(params[0], params[1], params[2], params[3]);
            } else if (params.length == 3) {
                ls = this.queryTableDictItemsByCode(params[0], params[1], params[2]);
            } else {
                // 字典Code格式不正确
                return null;
            }
        } else {
            // 字典表
            ls = this.queryDictItemsByCode(dictCode);
        }
        return ls;
    }

    /**
     * 通过查询指定table的 text code 获取字典
     * dictTableCache采用redis缓存有效期10分钟
     */
    @Deprecated
    private List<DictVO> queryTableDictItemsByCode(String tableFilterSql, String text, String code) {
        log.debug("无缓存dictTableList的时候调用这里！");
        String str = tableFilterSql + "," + text + "," + code;
        // 2.分割SQL获取表名和条件
        String table = null;
        String filterSql = null;
        if (tableFilterSql.toLowerCase().indexOf("where") > 0) {
            String[] arr = tableFilterSql.split(" (?i)where ");
            table = arr[0];
            filterSql = arr[1];
        } else {
            table = tableFilterSql;
        }
        // 3.SQL注入check
        SqlUtils.filterContentMulti(table, text, code);
        SqlUtils.specialFilterContentForDictSql(filterSql);
        // 4.针对采用 ${}写法的表名和字段进行转义和check
        table = SqlUtils.getSqlInjectTableName(table);
        text = SqlUtils.getSqlInjectField(text);
        code = SqlUtils.getSqlInjectField(code);
        // return sysDictMapper.queryTableDictItemsByCode(tableFilterSql,text,code);
        return sysDictMapper.queryTableDictWithFilter(table, text, code, filterSql);
    }

    private List<DictVO> queryTableDictItemsByCodeAndFilter(String table, String text, String code, String filterSql) {
        log.debug("无缓存dictTableList的时候调用这里！");
        // 1.SQL注入校验（只限制非法串改数据库）
        SqlUtils.specialFilterContentForDictSql(table);
        SqlUtils.filterContentMulti(text, code);
        SqlUtils.specialFilterContentForDictSql(filterSql);
        String str = table + "," + text + "," + code;
        // 3.针对采用 ${}写法的表名和字段进行转义和check
        table = SqlUtils.getSqlInjectTableName(table);
        text = SqlUtils.getSqlInjectField(text);
        code = SqlUtils.getSqlInjectField(code);
        return sysDictMapper.queryTableDictWithFilter(table, text, code, filterSql);
    }
}
